<?php
/*
  [EWEISHOP] Copyright(C) 2017 Elinkint Inc.
  This is NOT a freeware, use is subject to license terms

  WechatApi.php 2018-05-24 18:13 cunx $

*/

namespace common\library\amap;

use common\helpers\Http;

class AmapApi
{
    private static $PI = 3.14159265358979324;

    /**
     * 获取高德地图经纬度信息
     * @param string $key 高德地图key
     * @param string $address 详细地址
     * @return array $result 位置信息
     * @author lgt
     */
    public static function getLocation(string $key,string $address)
    {
        if (empty($key)) {
            return error('高德地图key不能为空');
        }
        //过滤地址信息的空格
        $address = str_replace(' ','',$address);

        //请求数据
        $url = "http://restapi.amap.com/v3/geocode/geo?address=".$address."&key=" . $key;
        $contents = Http::get($url);
        $result =  json_decode($contents,true);

        return $result;
    }

    /**
     * 获取两点之间的实际距离
     * @param string $key 高德地图key
     * @param string $startLocation 出发点坐标经纬度
     * @param string $destinationLocation 目的地坐标经纬度
     * @return array $result 距离信息
     * @author lgt
     */
    public static function getActualDistance(string $key,string $startLocation,string $destinationLocation)
    {
        if (empty($key)) {
            return error('高德地图key不能为空');
        }

        //请求数据
        $url = "http://restapi.amap.com/v3/distance?origins=".$startLocation."&destination=".$destinationLocation."&key=" . $key;
        $contents = Http::get($url);
        $result =  json_decode($contents,true);

        return $result;
    }

    /**
     * 判断坐标是否在圆内
     * @param array $point ['lng'=>'','lat'=>''] 指定点的坐标
     * @param array $circle array ['center'=>['lng'=>'','lat'=>''],'radius'=>'']  中心点和半径
     * @return bool false/true
     * @author lgt
     */
    public static function isPointInCircle($point, $circle){
        //获取两点之间的距离
        $distance = static::distance($point['lat'],$point['lng'],$circle['center']['lat'],$circle['center']['lng']);
        //和半径作比较，大于半径在圆外 否则在圆内
        if($distance <= $circle['radius']){
            return true;
        }else{
            return false;
        }
    }

    /**
     *  计算两个点之间的距离
     * @param float $centerLat  圆心点的纬度
     * @param float $centerLon  圆心点的经度
     * @param float $destinationLat  目的地点的纬度
     * @param float $destinationLon  目的地点的经度
     * @return float $distance 两点之间的距离
     * @author lgt
     */
    public static function distance($centerLat, $centerLon, $destinationLat, $destinationLon)
    {
        //地球半径
        $earthR = 6371000.;
        $x = cos($centerLat * static::$PI / 180.) * cos($destinationLat * static::$PI / 180.) * cos(($centerLon - $destinationLon) * static::$PI / 180);
        $y = sin($centerLat * static::$PI / 180.) * sin($destinationLat * static::$PI / 180.);
        $s = $x + $y;
        if ($s > 1) $s = 1;
        if ($s < -1) $s = -1;
        $alpha = acos($s);
        $distance = $alpha * $earthR;
        return $distance;
    }

    /**
     * 判断一个坐标是否在一个多边形内（由多个坐标围成的）
     * @param array $point 指定点坐标
     * @param array $coordinateGroup 多边形坐标 顺时针方向
     * @return bool false/true
     * @author lgt
     */
    public static function isPointInPolygon(array $point,array $coordinateGroup) {

        //没有传入指定点坐标
        if (empty($point)) {
            return false;
        }
        //没有传入区域坐标
        if (empty($coordinateGroup)) {
            return false;
        }

        //统计多边形坐标数量
        $count = count($coordinateGroup);
        //如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true
        $boundOrVertex = true;
        //交叉点数
        $intersectCount = 0;
        //浮点类型计算时候与0比较时候的容差
        $precision = 2e-10;

        //顶点1赋值
        $vertex_1 = $coordinateGroup[0];
        //检查所有的线
        for ($i = 1; $i <= $count; ++$i) {
            if ($point['lng'] == $vertex_1['lng'] && $point['lat'] == $vertex_1['lat']) {
                //指定点在顶点上
                //指定点在顶点上
                return $boundOrVertex; 
            }
            //顶点2赋值
            $vertex_2 = $coordinateGroup[$i % $count];
            //点不在第一条线上
            if ($point['lat'] < min($vertex_1['lat'], $vertex_2['lat']) || $point['lat'] > max($vertex_1['lat'], $vertex_2['lat'])) {
                //第二个顶点成为第一个顶点
                $vertex_1 = $vertex_2;
                continue;
            }

            //在两个顶点纬度之间
            if ($point['lat'] > min($vertex_1['lat'], $vertex_2['lat']) && $point['lat'] < max($vertex_1['lat'], $vertex_2['lat'])) {
                if($point['lng'] <= max($vertex_1['lng'], $vertex_2['lng'])){
                    //指定点在水平的线上
                    if ($vertex_1['lat'] == $vertex_2['lat'] && $point['lng'] >= min($vertex_1['lng'], $vertex_2['lng'])) {
                        return $boundOrVertex;
                    }

                    //垂直射线
                    if ($vertex_1['lng'] == $vertex_2['lng']) {
                        //指定点在垂直的线上
                        if ($vertex_1['lng'] == $point['lng']) {
                            return $boundOrVertex;
                        } else {
                            ++$intersectCount;
                        }
                    } else {
                        //经度的交点
                        $xinters = ($point['lat'] - $vertex_1['lat']) * ($vertex_2['lng'] - $vertex_1['lng']) / ($vertex_2['lat'] - $vertex_1['lat']) + $vertex_1['lng'];//cross point of lng
                        //指定点在线上
                        if (abs($point['lng'] - $xinters) < $precision) {
                            return $boundOrVertex;
                        }
                        //指定点在线前面
                        if ($point['lng'] < $xinters) {
                            ++$intersectCount;
                        }
                    }
                }
            } else {
                //指定点在除了顶点2以外的区域
                if ($point['lat'] == $vertex_2['lat'] && $point['lng'] <= $vertex_2['lng']) {
                    //下一个顶点
                    $vertex_3 = $coordinateGroup[($i+1) % $count];
                    if ($point['lat'] >= min($vertex_1['lat'], $vertex_3['lat']) && $point['lat'] <= max($vertex_1['lat'], $vertex_3['lat'])) { //p.lat lies between p1.lat & p3.lat
                        ++$intersectCount;
                    } else {
                        $intersectCount += 2;
                    }
                }
            }
            //第二个顶点成为第一个顶点
            $vertex_1 = $vertex_2;
        }

        //计算指定地点在的区域
        if ($intersectCount % 2 == 0) {//结果为偶数时在多边形外
            return false;
        } else { //结果为奇数时在多边形内
            return true;
        }
    }


}